package org.proteored.miapeapi.xml.msi.adapter;

import java.util.Date;
import java.util.List;
import java.util.Set;

import javax.xml.datatype.XMLGregorianCalendar;

import org.proteored.miapeapi.cv.ControlVocabularyManager;
import org.proteored.miapeapi.interfaces.Adapter;
import org.proteored.miapeapi.interfaces.DateAdapter;
import org.proteored.miapeapi.interfaces.MiapeDate;
import org.proteored.miapeapi.interfaces.Project;
import org.proteored.miapeapi.interfaces.Software;
import org.proteored.miapeapi.interfaces.ms.MSContact;
import org.proteored.miapeapi.interfaces.msi.IdentifiedPeptide;
import org.proteored.miapeapi.interfaces.msi.IdentifiedProteinSet;
import org.proteored.miapeapi.interfaces.msi.InputDataSet;
import org.proteored.miapeapi.interfaces.msi.InputParameter;
import org.proteored.miapeapi.interfaces.msi.MSIAdditionalInformation;
import org.proteored.miapeapi.interfaces.msi.MiapeMSIDocument;
import org.proteored.miapeapi.interfaces.msi.Validation;
import org.proteored.miapeapi.xml.msi.autogenerated.MSIIdentifiedProteinSet;
import org.proteored.miapeapi.xml.msi.autogenerated.MSIMIAPEMSI;
import org.proteored.miapeapi.xml.msi.autogenerated.ObjectFactory;
import org.proteored.miapeapi.xml.msi.autogenerated.ParamType;
import org.proteored.miapeapi.xml.msi.util.MSIControlVocabularyXmlFactory;

/**
 * Implementation of {@link MSIMIAPEMSI} from a {@link MiapeMSIDocument} object.
 * 
 * @author Salva
 * 
 */
public class MiapeMsiXMLAdapter implements Adapter<MSIMIAPEMSI> {
	private final ObjectFactory factory;
	private final MiapeMSIDocument document;
	private final MSIControlVocabularyXmlFactory cvFactory;
	private static org.apache.log4j.Logger log = org.apache.log4j.Logger
			.getLogger("log4j.logger.org.proteored");
	private boolean processPeptidesInParallel = true;

	public MiapeMsiXMLAdapter(MiapeMSIDocument document,
			ControlVocabularyManager controlVocabularyUtil) {
		factory = new ObjectFactory();
		this.document = document;
		cvFactory = new MSIControlVocabularyXmlFactory(factory,
				controlVocabularyUtil);
	}

	public MiapeMsiXMLAdapter(MiapeMSIDocument document,
			ControlVocabularyManager controlVocabularyUtil,
			boolean processPeptidesInParallel) {
		this(document, controlVocabularyUtil);
		this.processPeptidesInParallel = processPeptidesInParallel;
	}

	@Override
	public MSIMIAPEMSI adapt() {
		// log.info("Before Adapting MSI document to XML");
		MSIMIAPEMSI xmlMiape = factory.createMSIMIAPEMSI();
		log.info("Adding MiapeData");

		addMiapeData(xmlMiape);
		log.info("Adding IdentifiedProteins");
		Set<IdentifiedProteinSet> identifiedProteinSets = document
				.getIdentifiedProteinSets();
		if (identifiedProteinSets != null)
			addProteinSets(xmlMiape, identifiedProteinSets);

		log.info("Adding IdentifiedPeptides");
		List<IdentifiedPeptide> identifiedPeptides = document
				.getIdentifiedPeptides();
		if (identifiedPeptides != null)
			addPeptideSet(xmlMiape, identifiedPeptides);

		log.info("Adding getInputDataSets");
		Set<InputDataSet> inputDataSets = document.getInputDataSets();
		if (inputDataSets != null)
			addInputDataSets(xmlMiape, inputDataSets);
		log.info("Adding getInputParameters");

		Set<InputParameter> inputParameters = document.getInputParameters();
		if (inputParameters != null)
			addInputParameters(xmlMiape, inputParameters);

		log.info("Adding getMsiSoftwares");

		Set<Software> msiSoftwares = document.getSoftwares();
		if (msiSoftwares != null)
			addMsiSoftwares(xmlMiape, msiSoftwares);
		log.info("Adding Validations");

		Set<Validation> validations = document.getValidations();
		if (validations != null)
			addValidations(xmlMiape, validations);

		Set<MSIAdditionalInformation> additionalInformations = document
				.getAdditionalInformations();
		if (additionalInformations != null)
			addAdditionalInformations(xmlMiape.getMSIAdditionalInformation(),
					additionalInformations);

		return xmlMiape;
	}

	private void addProteinSets(MSIMIAPEMSI xmlMiape,
			Set<IdentifiedProteinSet> identifiedProteinSets) {
		if (identifiedProteinSets == null)
			return;
		for (IdentifiedProteinSet proteinSet : identifiedProteinSets) {
			// MSIIdentifiedProteinSet adapt = new
			// IdentifiedProteinSetParallelAdapter(proteinSet,
			// factory, cvFactory).adapt();
			MSIIdentifiedProteinSet adapt = new IdentifiedProteinSetAdapter(
					proteinSet, factory, cvFactory).adapt();
			xmlMiape.getMSIIdentifiedProteinSet().add(adapt);

		}

	}

	private void addPeptideSet(MSIMIAPEMSI xmlMiape,
			List<IdentifiedPeptide> identifiedPeptides) {
		if (identifiedPeptides == null || identifiedPeptides.isEmpty())
			return;
		log.info("Adapting " + identifiedPeptides.size() + " peptides");
		if (processPeptidesInParallel) {
			xmlMiape.setMSIIdentifiedPeptideSet(new IdentifiedPeptideSetParallelAdapter(
					identifiedPeptides, factory, cvFactory).adapt());
		} else {
			xmlMiape.setMSIIdentifiedPeptideSet(new IdentifiedPeptideSetAdapter(
					identifiedPeptides, factory, cvFactory).adapt());
		}
		log.info("Peptides adapted");
	}

	private void addAdditionalInformations(List<ParamType> xmlAddInfos,
			Set<MSIAdditionalInformation> addInfos) {
		if (addInfos == null)
			return;
		for (MSIAdditionalInformation addInfo : addInfos) {
			xmlAddInfos.add(new AdditionalInformationAdapter(addInfo, factory,
					cvFactory).adapt());
		}
	}

	private void addValidations(MSIMIAPEMSI xmlMiape,
			Set<Validation> validations) {
		if (validations == null)
			return;
		for (Validation validation : validations) {
			xmlMiape.getMSIValidation().add(
					new ValidationAdapter(validation, factory, cvFactory)
							.adapt());
		}
	}

	private void addMsiSoftwares(MSIMIAPEMSI xmlMiape,
			Set<Software> msiSoftwares) {
		if (msiSoftwares == null)
			return;
		for (Software software : msiSoftwares) {
			xmlMiape.getMSISoftware().add(
					new SoftwareMSIAdapter(software, factory, cvFactory)
							.adapt());

		}
	}

	private void addInputParameters(MSIMIAPEMSI xmlMiape,
			Set<InputParameter> inputParameters) {
		if (inputParameters == null)
			return;
		for (InputParameter inputParameter : inputParameters) {
			xmlMiape.getMSIInputParameters().add(
					new InputParameterAdapter(inputParameter, factory,
							cvFactory).adapt());
		}
	}

	private void addInputDataSets(MSIMIAPEMSI xmlMiape,
			Set<InputDataSet> inputDataSets) {
		if (inputDataSets == null)
			return;
		for (InputDataSet inputDataSet : inputDataSets) {
			xmlMiape.getMSIInputDataSet().add(
					new InputDataSetAdapter(inputDataSet, factory, cvFactory)
							.adapt());
		}
	}

	private void addMiapeData(MSIMIAPEMSI xmlMiape) {
		final int id = document.getId();
		if (id > 0) {
			xmlMiape.setId(id);
		} else {
			xmlMiape.setId(-1);
		}
		final MiapeDate date = document.getDate();
		if (date != null) {
			xmlMiape.setDate(date.getValue());
		}
		final Date modificationDate2 = document.getModificationDate();
		XMLGregorianCalendar modificationDate = new DateAdapter(
				modificationDate2).adapt();
		xmlMiape.setModificationDate(modificationDate);
		final MSContact contact = document.getContact();
		if (contact != null)
			xmlMiape.setMSIContact(new ContactAdapter(contact, factory,
					cvFactory).adapt());
		xmlMiape.setName(document.getName());
		xmlMiape.setAttachedFileLocation(document.getAttachedFileLocation());
		final Boolean template = document.getTemplate();
		if (template != null) {
			xmlMiape.setTemplate(template);
		} else {
			xmlMiape.setTemplate(Boolean.FALSE);
		}

		xmlMiape.setVersion(document.getVersion());
		final Project project = document.getProject();
		// even if project is null, create a project
		xmlMiape.setMIAPEProject(new ProjectAdapter(project, factory).adapt());
		if (modificationDate2 != null)
			xmlMiape.setModificationDate(new DateAdapter(modificationDate2)
					.adapt());
		xmlMiape.setGeneratedFilesDescription(document
				.getGeneratedFilesDescription());
		xmlMiape.setGeneratedFilesURL(document.getGeneratedFilesURI());
		final int msDocumentReference = document.getMSDocumentReference();
		if (msDocumentReference > 0)
			xmlMiape.setMIAPEMSRef(msDocumentReference);

	}

}
